<?php
/**
 * Class for working with image files.
 * Get all information about file, make Thumbnail, add Watermark and others
 *  
 * @package Library
 * @subpackage Image
 * @uses File 
 * @category File's modules
 */
class Image extends File
{
    //Local values.    
    var $h;
    var $w;

    /**
     * Image
     * Construct function for working with image
     * 
     * @param  $info array with image restrictions
     * @return File
     */
    function Image($info)
    {
        parent::File($info);
        $this->aLimits['PERMITTED_TYPES'] = $info['types'];
        $this->aLimits['FILE_MAX_SIZE']   = $info['max_size'];
        $this->aLimits['MAX_IMAGE_W']     = $info['max_w'];
        $this->aLimits['MAX_IMAGE_H']     = $info['max_h'];
        $this->aLimits['MIN_IMAGE_W']     = $info['min_w'];
        $this->aLimits['MIN_IMAGE_H']     = $info['min_h'];
    }

    /**
     * loadInfo
     * Loads info about image file into object var.
     * The function does not allow to upload images with undefined types.
     *
     * @param string $path to file
     * @return boolean result of operation
     */
    function loadInfo($path)
    {
        if (!parent::loadInfo($path))
            return false;

        if ($aInfo = @getImageSize($this->path))
        {
            $types = array('', 'gif', 'jpg', 'png', 'swf', 'psd', 'bmp', 'tiff', 'tiff', 'jpc', 'jp2', 'jpx', 'jb2', 'swc', 'iff', 'wbmp', 'xbm');

            $this->w = $aInfo[0];
            $this->h = $aInfo[1];
            $this->type = $types[$aInfo[2]];
            //PHP >= 4.3.0
            $this->mimeType = $aInfo['mime'];
            return true;
        }
        return $this->addError('image.unsupported_type', $this->getName());
    }

    /**
     * _checkLimits
     * Checks image and file parameters (size, dimensions, type) against config's min/max values
     *
     * @return boolean
     */
    function _checkLimits()
    {
        if (! parent::_checkLimits())
            return false;

        if ($this->aLimits['MAX_IMAGE_W'] && $this->w > $this->aLimits['MAX_IMAGE_W'])
            $this->addError('image.max_w', $this->aLimits['MAX_IMAGE_W'] );

        if ($this->aLimits['MIN_IMAGE_W'] && $this->w < $this->aLimits['MIN_IMAGE_W'])
            $this->addError('image.min_w', $this->aLimits['MIN_IMAGE_W'] );

        if ($this->aLimits['MAX_IMAGE_H'] && $this->h > $this->aLimits['MAX_IMAGE_H'])
            $this->addError('image.max_h', $this->aLimits['MAX_IMAGE_H'] );

        if ($this->aLimits['MIN_IMAGE_H'] && $this->h < $this->aLimits['MIN_IMAGE_H'])
            $this->addError('image.min_h', $this->aLimits['MIN_IMAGE_H'] );

        if ($this->aLimits['PERMITTED_TYPES'] && !in_array($this->type, $this->aLimits['PERMITTED_TYPES']))
            $this->addError('image.unsupported_type', $this->type);

        return (!$this->hasErrors());
    }

    /** 
     * addWatermark
     * Adds watermark to current image file     
     * 
     * @see http://www.sitepoint.com/article/watermark-images-php
     * @param string $wmPath path to _PNG-8_ image with watermark
     * @return boolean
     */
    function addWatermark($wmPath)
    {

        $hWm   = imageCreateFromPng($wmPath);
        $w     = imageSx($hWm);
        $h     = imageSy($hWm);
        $hImg  = $this->_createImg();

        $destX = $this->w - $w - 5;
        $destY = $this->h - $h - 5;
        imageCopyMerge($hImg, $hWm, $destX, $destY, 0, 0, $w, $h, 100);

        imageJpeg($hImg, $this->path);

        imageDestroy($hImg);
        imageDestroy($hWm);

        return true;
    }

    /**
     * _createImg
     * Returns image handler by image type
     *
     * @return integer resource
     */
    function _createImg()
    {
        $hImg = 0;
        switch ($this->type)
        {
            case 'gif':
                $hImg = imageCreateFromGif($this->path);
                break;
            case 'png':
                $hImg = imageCreateFromPng($this->path);
                break;
            default:
                $hImg = imageCreateFromJpeg($this->path);
        }
        return $hImg;
    }

    /** 
     * makeThumbnail
     * Resizes image and writes to file
     * 
     * @param int $path   image file destination
     * @param int $maxW   maximum width
     * @param int $maxH   maximum height
     * @param string $driver   transformation driver code ( gd, im)
     * @param array $driverParams   driver specific params ( e.g for IM path and quality)
     * @return float ratio in % beetwen full image and thumbnail
     */
    function makeThumbnail($path, $maxW, $maxH, $driver='gd', $driverParams=array())
    {
        list($nNewW, $nNewH) = $this->_calcSize($maxW, $maxH);
        switch ($driver)
        {
            case 'im': //image magic
               $sCmd  = '"'.$driverParams['path'].'"'; // //full path to ImageMagick's convert utility
               $sCmd .= ' -geometry '.$nNewW.'x'.$nNewH;
               if ('jpg' == $this->type)
                   $sCmd .= ' -quality '.$driverParams['quality'];
               $sCmd .= ' "'.escapeshellcmd($this->path).'" "'.escapeshellcmd($path).'"';
               exec($sCmd);
            break;
            case 'gd':
            default:
                $hFrm = $this->_createImg();
                $hTo = ImageCreateTrueColor($nNewW, $nNewH);
                imageCopyResampled($hTo, $hFrm, 0, 0, 0, 0, $nNewW, $nNewH, $this->w, $this->h);
                switch ($this->type)
                {
                    case 'gif':
                    case 'png':
                        imagepng($hTo, $path);
                        break;
                    default:
                       imagejpeg($hTo, $path);
                }
                imageDestroy($hTo);
                imageDestroy($hFrm);
        }
        return ($nNewW * $nNewH)/($this->w * $this->h);
    }

    /** 
     * _calcSize
     * Calculates size for resizing.
     * The function will not resize images which smaller that thumbnails.
     * 
     * @param int $maxW  maximum width
     * @param int $maxH  maximum height
     * @return array new size (width, height)
     * @see makeThumbnail()
     */
    function _calcSize($maxW, $maxH)
    {
        $w  = $maxW;
        $h  = $maxH;

        if ($this->w > $maxW)
        {
            $w  = $maxW;
            $h  = floor($this->h * $maxW/$this->w);
            if ($h > $maxH)
            {
              $h  = $maxH;
              $w  = floor($this->w * $maxH/$this->h);
            }
        }
        elseif ($this->h > $maxH)
        {
            $h  = $maxH;
            $w  = floor($this->w * $maxH/$this->h);
        }
        elseif ($this->w < $maxW)
        {
            $w  = $maxW;
            $h  = floor($this->h * $maxW/$this->w);
            if ($h > $maxH)
            {
              $h  = $maxH;
              $w  = floor($this->w * $maxH/$this->h);
            }
        }
        elseif ($this->h < $maxH)
        {
            $h  = $maxH;
            $w  = floor($this->w * $maxH/$this->h);
        }
        return array($w, $h);
    }

    /**
     * createSecurityImage
     * Creates and outputs Security Image     
     *
     * @param string $sString Security String (generated by securityimg.php)
     * @param array $aFonts TrueType fonts filenames as hash
     * @param integer $iTextImgWidth Image Width
     * @param integer $iTextImgHeight Image Height
     * @param integer $iTextLeftOffset Text Left Offset
     * @param integer $iTextTopOffset Text Top Offset
     * @param integer $iTextSize Text Size in pixels, only for true-type fonts
     * @param integer $iBorderSize Image Border Size
     * @param integer $iTextCharSpace Space between characters
     */
    function createSecurityImage($sString, $aFonts = array(), $iTextImgWidth = 135, $iTextImgHeight = 40, $iTextLeftOffset = 20, $iTextTopOffset = 8, $iTextSize = 50, $iBorderSize = 2, $iTextCharSpace = 35)
    {
        /**
         * Checking if parameters fit image size, changing font size and spacing if not
         */
        if ( ((($iTextSize / 2) * strlen($sString) +  $iTextCharSpace * (strlen($sString) - 1) ) > $iTextImgWidth * 0.92) or (  $iTextCharSpace * (strlen($sString) - 1) > $iTextImgWidth * 0.92  ) )
        {
            $iTextSize = intval( $iTextImgWidth * 0.95 / strlen($sString) / 2.2 );
            $iTextCharSpace = ( ($iTextImgWidth - $iTextLeftOffset * 2 - $iBorderSize * 2) - (strlen($sString) * $iTextSize * 0.1)  ) /  (strlen($sString) - 1) + 1;
        }

        /**
         * Checking if height is OK
         */
        if ($iTextImgHeight < $iTextSize)
        {
            $iTextImgHeight = $iTextSize * 5;
        }

        /**
         * Decreasing border by one, that it will fit real pixels value
         */
        $iBorderSize--;

        /**
         * Trying to use default fonts, if such files exist
         */
        if ($aFonts)
        {
            foreach ($aFonts as $key=>$value)
            {
                if (!file_exists($value))
                {
                    unset($aFonts[$key]);
                }
            }
        }

        /**
         * Creating Image Instances
         */
        $hImage = imagecreate($iTextImgWidth, $iTextImgHeight);
        $hTempImage  = imagecreate($iTextLeftOffset, $iTextTopOffset);

        $hBgColor = imagecolorallocate ($hTempImage, 250, 250, 250); //light gray background

        imagefill($hTempImage, 0, 0, $hBgColor); // For GD2+

        imagecopyresized($hImage, $hTempImage, 0, 0, 0, 0, $iTextImgWidth, $iTextImgHeight, $iTextLeftOffset, $iTextTopOffset);
        imagedestroy($hTempImage);

        $hTextColor = imagecolorallocate ($hImage, 86, 86, 86);

        $iCharSpacing = $iTextLeftOffset;

        /**
         * If have TrueType Fonts, then use it
         */
        if ($aFonts)
        {
            for ($x = 0; $x < strlen($sString); $x++)
            {
                /** Paste string */
                imagefttext($hImage, $iTextSize+rand(3,5), rand(-30,30), $iCharSpacing, $iTextImgHeight/2+$iTextSize/2, $hTextColor, $aFonts[rand(0,count($aFonts)-1)], $sString[$x]);
                $iCharSpacing += $iTextCharSpace;
            }
        }
        /**
         * Or don't use, if don't have
         */
        else
        {
            $nTxtColor = imagecolorallocate($hImage, 86, 86, 86);
            $sTempString = '';
            /**
             * Adding spaces between symbols
             */
            for ($i = 0; $i < strlen($sString); $i++)
            {
                $sTempString .= $sString[$i];
                if ($i != strlen($sString) - 1)
                {
                    $sTempString .= ' ';
                }
            }
            $sString = $sTempString;
            unset($sTempString);
            /** Paste string */
            imagestring($hImage, 5, $iTextImgWidth / 2 - strlen($sString) * 9 / 2, $iTextImgHeight / 2 - $iTextImgHeight * 0.10, $sString, $nTxtColor);
        }

        /**
         * Drawing random pixels
         */
        $hTextColor = imagecolorallocate ($hImage, 86, 86, 86);
        $iPixels = ($iTextImgWidth - $iBorderSize)* ($iTextImgHeight - $iBorderSize) / 30;
        for($i = 0; $i < $iPixels; $i++){
            imagesetpixel($hImage, rand($iBorderSize, $iTextImgWidth-$iBorderSize), rand($iBorderSize, $iTextImgHeight-$iBorderSize), $hTextColor);
        }

        /**
         * Drawing waves
         */
        // get multipliers for waves
        $iWaveNum = 3;
        $iWaveMultiplier = ($iWaveNum * rand(0,360)) / ($iTextImgWidth-$iBorderSize);

//        // cosine wave
//        $hTextColor = imagecolorallocate ($hImage, 192, 192, 192);
//        $iRandNum = rand(4, 6);
//        $iCurX = $iRandNum;
//        $iCurY = $iTextImgHeight-$iRandNum;
//        for($pt = $iRandNum; $pt < $iTextImgWidth-$iRandNum; $pt++)
//        {
//            $newX = $iCurX + $iRandNum;
//            $newY = (($iTextImgHeight-$iRandNum)/rand(1,1)) + (cos(deg2rad($newX * $iWaveMultiplier)) * (($iTextImgHeight-$iRandNum)/rand(1,2)));
//            imageline($hImage, $iCurX, $iCurY, $newX, $newY, $hTextColor);
//            $iCurX = $newX;
//            $iCurY = $newY;
//        }
//
//        // sine wave
//        $iCurX = $iRandNum;
//        $iCurY = $iRandNum;
//        for($pt = $iRandNum; $pt < $iTextImgWidth-$iRandNum; $pt++)
//        {
//            $newX = $iCurX+$iRandNum;
//            $newY = (($iTextImgHeight-$iRandNum)/rand(1,1)) + (sin(deg2rad($newX * $iWaveMultiplier - 90)) * (($iTextImgHeight-$iRandNum)/rand(1,2)));
//            imageline($hImage, $iCurX, $iCurY, $newX, $newY, $hTextColor);
//            $iCurX = $newX;
//            $iCurY = $newY;
//        }
//
        // draw line
        imageline($hImage, 0, rand(10, $iTextImgHeight - 10), $iTextImgWidth, rand(10, $iTextImgHeight - 10), $hTextColor);

        $iRandNum = rand(4, 6);

        $iCurX = $iRandNum;
        $iCurY = $iRandNum;
        for($pt = $iRandNum; $pt < $iTextImgWidth-$iRandNum; $pt++)
        {
            $newX = $iCurX + $iRandNum - 2;
            $newY = (($iTextImgHeight-$iRandNum)/rand(1,1)) + (cos(deg2rad($newX * $iWaveMultiplier - 75)) * (($iTextImgHeight-$iRandNum)/rand(1,2)));
            imageline($hImage, $iCurX, $iCurY, $newX, $newY, $hTextColor);
            $iCurX = $newX;
            $iCurY = $newY;
        }

        /**
         * Drawing borders
         */
        $hColor = imagecolorallocate ($hImage, 90, 90, 90);
        imagefilledrectangle($hImage, 0, 0, $iBorderSize, $iTextImgHeight, $hColor);
        imagefilledrectangle($hImage, 0, 0, $iTextImgWidth, $iBorderSize, $hColor);
        imagefilledrectangle($hImage, $iTextImgWidth-$iBorderSize-1, 0, $iTextImgWidth, $iTextImgHeight, $hColor);
        imagefilledrectangle($hImage, 0, $iTextImgHeight-$iBorderSize-1, $iTextImgWidth, $iTextImgHeight, $hColor);


        header('Content-Type: image/jpeg');
        imagejpeg($hImage);
    }
}